
// TypeMap
template < typename ... Tail >
struct Holder;

template <typename ValueType, typename Head, typename ... Tail >
struct Holder<ValueType, Head, Tail ... > :
    public Holder<ValueType, Head>,
    public Holder<ValueType, Tail ... >
{};

template <typename ValueType, typename Head >
struct Holder<ValueType, Head>
{
    ValueType value;
};

template < typename ... Types >
struct TypeMap;

template <typename ValueType, typename ... Types >
struct TypeMap<ValueType, Types ... > :
    public Holder<ValueType, Types ... >
{
    template <typename T>
    void set(const ValueType& value)
    {
        ((Holder<ValueType, T>*)this)->value = value;
    }
        
    template <typename T>
    ValueType get()
    {
        return ((Holder<ValueType, T>*)this)->value;
    }
};

// Objectives
template <typename Criterion> struct Maximize : public Criterion {};
template <typename Criterion> struct Minimize : public Criterion {};

// Criteria
struct Criterion1{ double operator()(){ return 0; }};
struct Criterion2{ double operator()(){ return 0; }};

// Pareto rule
template < typename ... Types > struct Pareto;

template < typename T, typename ... Types >
struct Pareto<Minimize<T>, Types ... >
{
    template< typename Map >
	bool operator()(Map& oldResult, Map& newResult)
	{
	    typedef Minimize<T> Criterion;
	    Criterion criterion;
	    
	    newResult.template set<Criterion>( criterion() );
	    
	    if(newResult.template get<Criterion>() >= oldResult.template get<Criterion>())
	        return false;
	    
	    Pareto<Types ... > pareto;
	    return pareto(oldResult, newResult);
	}
};

template < typename T, typename ... Types >
struct Pareto<Maximize<T>, Types ... >
{
    template< typename Map >
	bool operator()(Map& oldResult, Map& newResult)
	{
	    typedef Maximize<T> Criterion;
	    Criterion criterion;
	    
	    newResult.template set<Criterion>( criterion() );
	    
	    if(newResult.template get<Criterion>() <= oldResult.template get<Criterion>())
	        return false;
	    
	    Pareto<Types ... > pareto;
	    return pareto(oldResult, newResult);
	}
};

template<>
struct Pareto<>
{
    template<typename Map>
    bool operator()(Map& oldResult, Map& newResult)
    {
        oldResult = newResult;
        return true;
    }
};

int main()
{
    TypeMap<double, Minimize<Criterion1>, Maximize<Criterion2>> oldResult, newResult;
    
    Pareto<Minimize<Criterion1>, Maximize<Criterion2>> pareto;
    pareto(oldResult, newResult);
}
